package com.love.cloud.admin.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.love.cloud.admin.api.constants.DingTalkConstants;
import com.love.cloud.admin.api.dto.*;
import com.love.cloud.admin.api.entity.*;
import com.love.cloud.admin.config.properties.SosUserBaseProperties;
import com.love.cloud.admin.mapper.DingTalkAsyncMapper;
import com.love.cloud.admin.mapper.SysUserDeptMapper;
import com.love.cloud.admin.service.*;
import com.love.cloud.common.core.constant.CommonConstants;
import com.love.cloud.common.core.exception.BusinessException;
import com.love.cloud.common.core.util.RedisUtils;
import com.love.cloud.common.zzd.api.GovDingAPICaller;
import com.love.cloud.common.zzd.dto.DingTalkOrgDto;
import com.love.cloud.common.zzd.dto.DingTalkUserDto;
import com.love.cloud.common.zzd.dto.UserInfoByCodeDto;
import com.love.cloud.common.zzd.properties.DingTalkProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author hongdongqu
 */
@Service
@Slf4j
public class DingTalkServiceImpl implements DingTalkService {
    //同步锁
    private static String asyncLockKey="asyncLock";
    //部门id关系redis中的hashKey
    private static String deptIdsHashKey="deptIds";
    //用户id关系redis中的hashKey
    private static String userIdsHashKey="userIds";
    //用户部门关系redis中的hashKey
    private static String deptUserHashKey="userDept";
    //用户名称redis中的hashKey
    private static String userNameHashKey="userNames";

    private static List<SysUser> syncSaveUserList=new ArrayList<>();

    private static List<SysUserDept> syncSaveUserDeptList=new ArrayList<>();

    private static List<SysUserRole> syncSaveUserRoleList=new ArrayList<>();

    @Resource
    private DingTalkProperties dingTalkProperties;
    @Resource
    private DingTalkAsyncMapper dingTalkAsyncMapper;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysDeptService sysDeptService;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private SysUserDeptMapper sysUserDeptMapper;
    @Resource
    private SysUserDeptService sysUserDeptService;
    @Resource
    private GovDingAPICaller govDingAPICaller;
    @Resource
    private AsyncDingTalkService asyncDingTalkService;
    @Resource
    private SysRoleZzdUserService sysRoleZzdUserService;
    @Resource
    private SosUserBaseProperties sosUserBaseProperties;
    @Resource
    private ThreadPoolTaskExecutor taskExecutor;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private SysUserRoleService sysUserRoleService;


    @Override
    public Object getZZDParams() {
        ZDingTalkParamsDto zDingTalkParamsDto =new ZDingTalkParamsDto();
        zDingTalkParamsDto.setAppId(dingTalkProperties.getAppId());
        zDingTalkParamsDto.setAppKey(dingTalkProperties.getAppKey());
        zDingTalkParamsDto.setAppSecret(dingTalkProperties.getAppSecret());
        String qrCodeSrc = dingTalkProperties.getQrCodeSrc();
        qrCodeSrc=qrCodeSrc.replace("${appId}",dingTalkProperties.getAppId());
        qrCodeSrc=qrCodeSrc.replace("${redirectUri}",dingTalkProperties.getRedirectUri());
        zDingTalkParamsDto.setQrCodeSrc(qrCodeSrc);
        return zDingTalkParamsDto;
    }
    @Override
    @Async("taskExecutor")
    @Transactional(rollbackFor = Exception.class)
    public void asyncAllData(){
        this.syncAllData(null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncAllData(){
        this.syncAllData(null);
    }

    @Override
    @Async("taskExecutor")
    @Transactional(rollbackFor = Exception.class)
    public void asyncDataByDeptId(Long deptId) {
        this.syncAllData(deptId);
    }

    @Override
    public SysUser parseZZDingQrCode(String QRCode,boolean autoAdd) {
        if(StringUtils.isEmpty(QRCode)){
            throw new BusinessException("请传入用户信息");
        }
        UserInfoByCodeDto userInfoDtoByCode = govDingAPICaller.getUserInfoDtoByCode(QRCode);
        if(userInfoDtoByCode==null){
            throw new RuntimeException("获取到用户信息为空");
        }
        return handleParseKey(userInfoDtoByCode,autoAdd);
    }

    @Override
    public SysUser ZZDingFreeLogin(String authCode) {
        if(StringUtils.isEmpty(authCode)){
            throw new BusinessException("请传入免登授权");
        }
        UserInfoByCodeDto dingTalkAppUserDto = govDingAPICaller.getDingTalkAppUserDto(authCode);
        if(dingTalkAppUserDto==null){
            throw new RuntimeException("获取到用户信息为空");
        }
        return handleParseKey(dingTalkAppUserDto,false);
    }

    @Override
    public SysUser addUserByAccountId(String accountId,String employeeCode) {
        //获取到浙政钉用户和该系统的角色绑定关系
        QueryWrapper<SysRoleZzdUser> roleZzdUserQueryWrapper=new QueryWrapper<>();
        roleZzdUserQueryWrapper.lambda().eq(SysRoleZzdUser::getZDingAccountId,accountId);
        List<SysRoleZzdUser> sysRoleZzdUserList = sysRoleZzdUserService.list(roleZzdUserQueryWrapper);
        if(sysRoleZzdUserList==null||sysRoleZzdUserList.size()==0){
            throw new RuntimeException("当前用户没有权限");
        }
        SysRoleZzdUser sysRoleZzdUser=new SysRoleZzdUser();
        sysRoleZzdUser.setRoleId(sosUserBaseProperties.getRoleId());
        sysRoleZzdUserList.add(sysRoleZzdUser);
        List<Long> deptData = new ArrayList<>();
        deptData.add(sosUserBaseProperties.getDeptId());
        //当员工id为空时候通过浙政钉id来获取到员工编码
        if(StringUtils.isEmpty(employeeCode)){
            employeeCode= govDingAPICaller.getEmployeeCodeByAccountId(accountId);
        }
        //员工编号
        Map<String,Object> userParamMap=new HashMap<>();
        userParamMap.put("empCode",employeeCode);
        DingTalkUserDto userInfo = govDingAPICaller.getDingTalkUserDtoByCode(employeeCode);
        if(userInfo!=null){
            SysUser sysUser = this.handleSaveUserData(userInfo, sysRoleZzdUserList, employeeCode);
            return sysUser;
        }
        return null;
    }


    /**
     * 新版执行解析
     * @param userInfoByCodeDto
     * @param autoAdd
     * @return
     */
    private SysUser handleParseKey(UserInfoByCodeDto userInfoByCodeDto,boolean autoAdd){
        //获取到账户id
        if(StringUtils.isEmpty(userInfoByCodeDto.getAccountId())){
            throw new RuntimeException("获取到浙政钉用户数据异常，请联系管理员");
        }
        //通过浙征钉的账户id获取到本地存储的用户信息
        QueryWrapper<SysUser> queryWrapper=new QueryWrapper<>();
        queryWrapper.lambda().eq(SysUser::getZDingAccountId,userInfoByCodeDto.getAccountId());
        SysUser one = sysUserService.getOne(queryWrapper);
        if(autoAdd&&one==null){
            //获取到浙政钉用户和该系统的角色绑定关系
            QueryWrapper<SysRoleZzdUser> roleZzdUserQueryWrapper=new QueryWrapper<>();
            roleZzdUserQueryWrapper.lambda().eq(SysRoleZzdUser::getZDingAccountId,userInfoByCodeDto.getAccountId());
            List<SysRoleZzdUser> sysRoleZzdUserList = sysRoleZzdUserService.list(roleZzdUserQueryWrapper);
            if(sysRoleZzdUserList==null||sysRoleZzdUserList.size()==0){
                throw new RuntimeException("当前用户没有权限");
            }
            SysRoleZzdUser sysRoleZzdUser=new SysRoleZzdUser();
            sysRoleZzdUser.setRoleId(sosUserBaseProperties.getRoleId());
            sysRoleZzdUserList.add(sysRoleZzdUser);
            //获取到用户的具体信息
            DingTalkUserDto userInfo = govDingAPICaller.getDingTalkUserDtoByCode(userInfoByCodeDto.getEmployeeCode());
            SysUser sysUser = this.handleSaveUserData(userInfo, sysRoleZzdUserList, userInfoByCodeDto.getEmployeeCode());
            return sysUser;
        }
        return one;
    }

    /**
     * 新版的保存用户信息
     * @param userInfo
     * @param sysRoleZzdUserList
     * @param employeeCode
     * @return
     */
    private SysUser handleSaveUserData(DingTalkUserDto userInfo,List<SysRoleZzdUser> sysRoleZzdUserList,String employeeCode){
        if(userInfo!=null){
            //角色数据
//                        List<Long> roleData=new ArrayList<>();
//                        roleData.add(1L);
            List<Long> roleData = sysRoleZzdUserList.stream().map(SysRoleZzdUser::getRoleId).collect(Collectors.toList());
            //从钉钉中获取到组织信息，并添加，然后返回本系统的id
            List<Long> deptData = this.syncDingOrg(employeeCode);
            //创建默认用户
            UserDTO userDTO=new UserDTO();
            userDTO.setName(userInfo.getEmployeeName());
            userDTO.setZDingAccountId(userInfo.getAccountId());
            userDTO.setZDingEmployeeCode(userInfo.getEmployeeCode());
            //保存浙政钉文件id
            userDTO.setZDingAvatarId(userInfo.getGovEmpAvatar());
            userDTO.setEmpBudgetedPostCode(userInfo.getEmpBudgetedPostCode());
            userDTO.setUsername(userInfo.getEmployeeName());
            userDTO.setPassword(sosUserBaseProperties.getDefaultPassword());
            userDTO.setStatus(CommonConstants.STATUS_NORMAL);
            userDTO.setSource(CommonConstants.SOURCE_DING);
            userDTO.setRole(roleData);
            userDTO.setDept(deptData);
            SysUser sysUser= sysUserService.saveUser(userDTO);
            return sysUser;
        }
        return null;
    }

    /**
     * 同步对应的用户的钉钉部门数据
     * @param employeeCode
     * @return
     */
    private List<Long> syncDingOrg(String employeeCode){
        List<DingTalkOrgDto> userOrgList = govDingAPICaller.getUserOrgList(employeeCode);
        List<SysDept> sysDeptList=new ArrayList<>();
        Set<String> codeList = userOrgList.stream().map(DingTalkOrgDto::getOrganizationCode).collect(Collectors.toSet());
        QueryWrapper<SysDept> sysDeptQueryWrapper=new QueryWrapper<>();
        sysDeptQueryWrapper.lambda().in(SysDept::getDingTalkId,codeList);
        //获取到数据库中已有的部门
        List<SysDept> list = sysDeptService.list(sysDeptQueryWrapper);
        List<SysDept> existOrgList=new ArrayList<>();
        Map<String, List<SysDept>> orgGroupMap = list.stream().collect(Collectors.groupingBy(SysDept::getDingTalkId));
        for (DingTalkOrgDto dingTalkOrgDto :userOrgList) {
            if(orgGroupMap.get(dingTalkOrgDto.getOrganizationCode())!=null){
                existOrgList.addAll(orgGroupMap.get(dingTalkOrgDto.getOrganizationCode()));
                continue;
            }
            //获取到顶级组织的数据,
            String path = this.syncSuperiorOrg(dingTalkOrgDto);
            SysDept sysDept=new SysDept();
            sysDept.setSource(CommonConstants.SOURCE_DING);
            sysDept.setParentId(0L);
            sysDept.setAsyncPathId(path);
            sysDept.setName(dingTalkOrgDto.getOrganizationName());
            sysDept.setFirstSpell(PinyinUtil.getFirstLetter(dingTalkOrgDto.getOrganizationName(),""));
            sysDept.setSpell(PinyinUtil.getPinyin(dingTalkOrgDto.getOrganizationName(),""));
            sysDept.setDingTalkId(dingTalkOrgDto.getOrganizationCode());
            sysDept.setDivision(dingTalkOrgDto.getDivisionCode());
            sysDept.setAsyncPid(dingTalkOrgDto.getParentCode());
            sysDept.setOrgCode(dingTalkOrgDto.getInstitutionCode());
            sysDept.setPostalCode(dingTalkOrgDto.getPostalCode());
            sysDept.setSort(Integer.valueOf(dingTalkOrgDto.getDisplayOrder()));
            sysDeptList.add(sysDept);
        }
        if(sysDeptList.size()>0){
            //新增部门信息
            sysDeptService.saveBatch(sysDeptList);
        }
        List<Long> collect = sysDeptList.stream().map(SysDept::getId).collect(Collectors.toList());
        if(existOrgList.size()>0){
            //将已经保存的部门数据再添加
            List<Long> collect2 = existOrgList.stream().map(SysDept::getId).collect(Collectors.toList());
            collect.addAll(collect2);
        }
        return collect;
    }


    /**
     * 同步上级组织
     * @param dingTalkOrgDto
     * @return
     */
    private String syncSuperiorOrg(DingTalkOrgDto dingTalkOrgDto){
        String path="";
        try {
            String[] superiorLine = govDingAPICaller.getSuperiorLine(dingTalkOrgDto.getOrganizationCode());
            if(superiorLine!=null&&superiorLine.length>0){
                path = "/"+StringUtils.join(superiorLine, "/")+"/"+dingTalkOrgDto.getOrganizationCode();
            }
            //开启异步任务去同步上级的部门
            asyncDingTalkService.asyncSuperiorOrgData(dingTalkOrgDto.getOrganizationCode(),superiorLine);
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return path;
    }



    /**
     * 同步全部数据
     * @param deptId
     */
    private void syncAllData(Long deptId){

        //如果传入组织id
        String orgCode="";
        if(deptId!=null){
            SysDept sysDept = sysDeptService.getById(deptId);
            if(sysDept!=null){
                String dingTalkId = sysDept.getDingTalkId();
                if(StringUtils.isNotEmpty(dingTalkId)){
                    orgCode=dingTalkId;
                }else{
                    log.warn("指定部门同步：获取到钉组件的组织id为空");
                    return;
                }
            }else{
                log.warn("指定部门同步：获取到部门信息失败");
                return;
            }
        }
        RLock lock = redissonClient.getLock(asyncLockKey+"::redisson");
        //只运行一个进程在同步数据
        try {
            boolean b = lock.tryLock();
            if(!b){
                log.info("上个钉钉同步尚未完成");
                return;
            }
            this.syncUserData(orgCode);
            log.info("钉钉同步完成");
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        } finally {
            this.delRedisData();
            this.syncSaveUserDeptList.clear();
            this.syncSaveUserList.clear();
            this.syncSaveUserRoleList.clear();
            lock.unlock();
        }

    }

    /**
     * 同步用户
     * @param orgCode
     */
    private void syncUserData(String orgCode){
        //清理集合
        this.syncSaveUserDeptList.clear();
        this.syncSaveUserList.clear();
        this.syncSaveUserRoleList.clear();
        //获取到到同步类型
        QueryWrapper<DingTalkAsync> queryWrapper=new QueryWrapper<>();
        queryWrapper.lambda().eq(DingTalkAsync::getAsyncType, DingTalkConstants.ASYNC_TYPE_USER);
        DingTalkAsync dingTalkAsync = dingTalkAsyncMapper.selectOne(queryWrapper);
        if(dingTalkAsync==null){
            dingTalkAsync=new DingTalkAsync();
            dingTalkAsync.setAsyncType(DingTalkConstants.ASYNC_TYPE_USER);
        }
        //添加数据库中的缓存数据
        this.setRedisData();
        //处理历史数据
        //this.handleHisData(dingTalkAsync,"sys_user",false);
        List<Long> roleData=new ArrayList<>();
        roleData.add(1L);
        if(StringUtils.isEmpty(orgCode)){
            orgCode=dingTalkProperties.getRootOrgCode();
        }
        //从缓存中获取到部门数据
        Object deptData = redisUtils.hget(deptIdsHashKey, orgCode);
        SysDept sysDept = null;
        if(deptData!=null&&deptData instanceof SysDept){
            sysDept=(SysDept) deptData;
        }
        if(sysDept==null){
            sysDept=new SysDept();
            //如果是根节点
            if(orgCode.equals(dingTalkProperties.getRootOrgCode())){
                //从浙政钉中获取到当前组织的信息然后添加
                DingTalkOrgDto orgItem = govDingAPICaller.getOrgInfoByCode(orgCode);
                //添加顶级的部门级别
                sysDept.setParentId(0L);
                sysDept.setId(IdWorker.getId(sysDept));
                sysDept.setPath("/"+sysDept.getId());
                sysDept.setSource(CommonConstants.SOURCE_DING);
                sysDept.setName(orgItem.getOrganizationName());
                sysDept.setFirstSpell(PinyinUtil.getFirstLetter(orgItem.getOrganizationName(),""));
                sysDept.setSpell(PinyinUtil.getPinyin(orgItem.getOrganizationName(),""));
                sysDept.setDingTalkId(orgItem.getOrganizationCode());
                sysDept.setAsyncPid(orgItem.getParentCode());
                sysDept.setId(IdWorker.getId(sysDept));
                sysDept.setAsyncPathId("");
                sysDept.setAsyncPathName("");
                sysDept.setOrgCode(orgItem.getInstitutionCode());
                sysDept.setPostalCode(orgItem.getPostalCode());
                sysDept.setSort(Integer.valueOf(orgItem.getDisplayOrder()));
                this.sysDeptService.save(sysDept);
                redisUtils.hset(deptIdsHashKey,sysDept.getDingTalkId(),sysDept);
            }else{
                //todo 不是根节点的部门
            }
        }
        this.syncDept(sysDept,roleData);
        log.info("开始执行保存数据三个集合数据分别是 syncSaveUserList::"+syncSaveUserList.size()+"; syncSaveUserDeptList::"+syncSaveUserDeptList.size()+"; syncSaveUserRoleList::"+syncSaveUserRoleList.size());
        //保存三个集合的数据
        if(syncSaveUserList.size()>0){
            this.sysUserService.saveBatch(syncSaveUserList);
        }if(syncSaveUserDeptList.size()>0){
            this.sysUserDeptService.saveBatch(syncSaveUserDeptList);
        }if(syncSaveUserRoleList.size()>0){
            this.sysUserRoleService.saveBatch(syncSaveUserRoleList);
        }
        if(dingTalkAsync.getId()!=null){
            dingTalkAsyncMapper.updateById(dingTalkAsync);
        }else{
            dingTalkAsyncMapper.insert(dingTalkAsync);
        }
    }

    /**
     * 设置redis的缓存
     */
    private void setRedisData(){
        this.delRedisData();
        //把数据库中获取到的用户信息放到redis中
        QueryWrapper<SysUser> userQueryWrapper=new QueryWrapper<>();
        userQueryWrapper.lambda().select(SysUser::getZDingAccountId,SysUser::getId,SysUser::getUsername,SysUser::getName)
                .eq(SysUser::getSource,CommonConstants.SOURCE_DING);
        List<SysUser> userList = this.sysUserService.list(userQueryWrapper);
        for (SysUser sysUser:userList) {
            redisUtils.hset(userIdsHashKey,sysUser.getZDingAccountId(),sysUser.getId());
            redisUtils.hset(userNameHashKey,sysUser.getName(),sysUser.getUsername());
        }
        //把数据库中获取到部门信息放到redis中
        QueryWrapper<SysDept> deptQueryWrapper=new QueryWrapper<>();
        deptQueryWrapper.lambda().select(SysDept::getDingTalkId,SysDept::getId,SysDept::getAsyncPathId,SysDept::getAsyncPathName,SysDept::getPath)
                .eq(SysDept::getSource,CommonConstants.SOURCE_DING);
        List<SysDept> deptList = this.sysDeptService.list(deptQueryWrapper);
        for (SysDept sysDept:deptList) {
            redisUtils.hset(deptIdsHashKey,sysDept.getDingTalkId(),sysDept);
        }

        //全部部门和用户的关系信息放到redis
        QueryWrapper<SysUserDept> deptUserQueryWrapper=new QueryWrapper<>();
        deptUserQueryWrapper.lambda().select(SysUserDept::getDeptId,SysUserDept::getUserId)
                .eq(SysUserDept::getSource,CommonConstants.SOURCE_DING);
        List<SysUserDept> deptUserList = this.sysUserDeptService.list(deptUserQueryWrapper);
        //把关系数据进行分组
        Map<Long, List<SysUserDept>> deptUserGroup = deptUserList.stream().collect(Collectors.groupingBy(SysUserDept::getDeptId));
        //把关系数据放到redis中
        for (Long deptId:deptUserGroup.keySet()) {
            for (SysUserDept item:deptUserGroup.get(deptId)) {
                redisUtils.hset(deptUserHashKey+"::"+item.getDeptId(),item.getUserId().toString(),item.getUserId());
            }
        }
    }

    /**
     * 删除redis中的对应数据
     */
    private void delRedisData(){
        //删除掉旧的redis信息
        if(redisUtils.hasKey(userIdsHashKey)){
            redisUtils.del(userIdsHashKey);
        }
        if(redisUtils.hasKey(deptIdsHashKey)){
            redisUtils.del(deptIdsHashKey);
        }
        if(redisUtils.hasKey(userNameHashKey)){
            redisUtils.del(userNameHashKey);
        }
        Set<String> keys = redisUtils.keys(deptUserHashKey + "*");
        if(keys!=null){
            for (String key:keys) {
                redisUtils.del(key);
            }
        }
    }

    /**
     * 同步部门数据（只做增量）
     * @param currentSysDept 当前部门信息
     */
    private void syncDept(SysDept currentSysDept,List<Long> roleData){
        List<DingTalkOrgDto> orgDtoList = govDingAPICaller.subOrganizationList(currentSysDept.getDingTalkId());
        //获取从到当前组织下的用户
        List<DingTalkUserDto> dingTalkUserDtoList = govDingAPICaller.organizationEmployeeList(currentSysDept.getDingTalkId());
        if(dingTalkUserDtoList!=null&&dingTalkUserDtoList.size()>0){
            //异步同步用户的数据
//            CompletableFuture.runAsync(() -> {
                this.syncUserData(dingTalkUserDtoList,currentSysDept,roleData);
            //},taskExecutor);
        }
        if(orgDtoList!=null&&orgDtoList.size()>0){
            List<SysDept> allSysDept=new ArrayList<>();
            List<SysDept> needSaveSysDept=new ArrayList<>();
            //先组装保持的对象
            for (DingTalkOrgDto orgItem :orgDtoList) {
                //从redis中获取到数据
                Object deptData = redisUtils.hget(deptIdsHashKey, orgItem.getOrganizationCode());
                SysDept sysDept = null;
                if(deptData!=null&&deptData instanceof SysDept){
                    sysDept=(SysDept) deptData;
                }
                if(sysDept==null){
                    sysDept=new SysDept();
                    sysDept.setId(IdWorker.getId(sysDept));
                    sysDept.setSource(CommonConstants.SOURCE_DING);
                    sysDept.setName(orgItem.getOrganizationName());
                    sysDept.setFirstSpell(PinyinUtil.getFirstLetter(orgItem.getOrganizationName(),""));
                    sysDept.setSpell(PinyinUtil.getPinyin(orgItem.getOrganizationName(),""));
                    sysDept.setDingTalkId(orgItem.getOrganizationCode());
                    sysDept.setAsyncPid(orgItem.getParentCode());
                    sysDept.setAsyncPathId(currentSysDept.getAsyncPathId()+"/"+currentSysDept.getDingTalkId());
                    sysDept.setAsyncPathName(currentSysDept.getAsyncPathName()+"/"+currentSysDept.getDingTalkId());
                    sysDept.setPath(currentSysDept.getPath()+"/"+sysDept.getId());
                    sysDept.setParentId(currentSysDept.getId());
                    sysDept.setOrgCode(orgItem.getInstitutionCode());
                    sysDept.setPostalCode(orgItem.getPostalCode());
                    try{
                        sysDept.setSort(Integer.valueOf(orgItem.getDisplayOrder()));
                    }catch (NumberFormatException ex){
                        //超出int长度时候设置下默认值
                        sysDept.setSort(9999);
                    }
                    needSaveSysDept.add(sysDept);
                    //把数据添加到redis的缓存中
                    redisUtils.hset(deptIdsHashKey,orgItem.getOrganizationCode(),sysDept);
                }
                allSysDept.add(sysDept);
            }
            //批量保存数据
            this.sysDeptService.saveBatch(needSaveSysDept);
            //递归开启子集部门的同步
            for (SysDept item :allSysDept) {
                this.syncDept(item,roleData);
            }
        }
    }

    /**
     * 同步用户数据
     * @param dingTalkUserDtoList
     */
    private void syncUserData(List<DingTalkUserDto> dingTalkUserDtoList,SysDept currentSysDept,List<Long> roleData){
        List<Long> deptData=new ArrayList<>();
        deptData.add(currentSysDept.getId());
        String deptUserKey=deptUserHashKey + "::" + currentSysDept.getId();
        for (DingTalkUserDto item :dingTalkUserDtoList) {
            Object userId = redisUtils.hget(userIdsHashKey, item.getAccountId());
            if(userId==null){
                //
                RLock lock = redissonClient.getLock("dingUserSyncLock::"+item.getAccountId());
                try {
                    //尝试加锁，等待对方锁释放
                    while (!lock.tryLock(5, 8, TimeUnit.SECONDS)) {
                        log.info("浙政钉id::"+item.getAccountId()+"加锁失败");
                    }
                    //做一下双重校验
                    //从redis中获取到数据
                    userId = redisUtils.hget(userIdsHashKey, item.getAccountId());
                    if(userId!=null){
                        //添加当前部门和对应的用户的关系
                        SysUserDept sysUserDept=new SysUserDept();
                        sysUserDept.setSource(CommonConstants.SOURCE_DING);
                        sysUserDept.setDeptId(currentSysDept.getId());
                        sysUserDept.setUserId((Long) userId);
                        syncSaveUserDeptList.add(sysUserDept);
                    }else{
                        UserDTO userDTO = new UserDTO();
                        userDTO.setName(item.getEmployeeName());
                        userDTO.setZDingAccountId(item.getAccountId());
                        userDTO.setZDingEmployeeCode(item.getEmployeeCode());
                        //保存浙政钉文件id
                        userDTO.setZDingAvatarId(item.getGovEmpAvatar());
                        userDTO.setEmpBudgetedPostCode(item.getEmpBudgetedPostCode());
                        userDTO.setUsername(item.getEmployeeName());
                        userDTO.setPassword(dingTalkProperties.getPassword());
                        userDTO.setStatus(CommonConstants.STATUS_NORMAL);
                        userDTO.setSource(CommonConstants.SOURCE_DING);
                        userDTO.setRole(roleData);
                        userDTO.setDept(deptData);
                        SysUser sysUser = sysUserService.getSaveUser(userDTO);
                        sysUser.setId(IdWorker.getId(sysUser));
                        Object userName = redisUtils.hget(userNameHashKey, sysUser.getUsername());
                        if(userName!=null){
                            sysUser.setUsername(sysUser.getName()+System.currentTimeMillis());
                        }
                        syncSaveUserList.add(sysUser);
                        if(roleData!=null&&roleData.size()>0){
                            //保存角色信息
                            List<SysUserRole> userRoleList = roleData.stream().map(roleId -> {
                                SysUserRole userRole = new SysUserRole();
                                userRole.setUserId(sysUser.getId());
                                userRole.setRoleId(roleId);
                                return userRole;
                            }).collect(Collectors.toList());
                            syncSaveUserRoleList.addAll(userRoleList);
                        }
                        if(deptData!=null&&deptData.size()>0){
                            //保存部门信息
                            List<SysUserDept> userDeptList = deptData.stream().map(deptId -> {
                                SysUserDept userDept = new SysUserDept();
                                userDept.setUserId(sysUser.getId());
                                userDept.setDeptId(deptId);
                                userDept.setSource(sysUser.getSource());
                                return userDept;
                            }).collect(Collectors.toList());
                            syncSaveUserDeptList.addAll(userDeptList);
                        }
                        //添加用户信息
                        redisUtils.hset(userIdsHashKey,item.getAccountId(),sysUser.getId());
                        redisUtils.hset(userNameHashKey,sysUser.getName(),sysUser.getUsername());
                    }
                }catch (Exception ex){
                  ex.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }else{
                //判断是否存在当前关系了
                Object deptUserData = redisUtils.hget(deptUserKey, ((Long)userId).toString());
                //如果不存在就添加当前用户对于的部门关系
                if(deptUserData==null){
                    SysUserDept sysUserDept=new SysUserDept();
                    sysUserDept.setUserId((Long) userId);
                    sysUserDept.setDeptId(currentSysDept.getId());
                    sysUserDept.setSource(CommonConstants.SOURCE_DING);
                    syncSaveUserDeptList.add(sysUserDept);
                }else{
                    //移除匹配上的数据
                    redisUtils.hdel(deptUserKey,((Long)userId).toString());
                }
            }
        }
        //先删除掉其中未匹配的数据
        Map<Object, Object> deptGroup = redisUtils.hmget(deptUserKey);
        if (deptGroup!=null&&deptGroup.size()>0) {
            //直接物理删除掉关系表单的数据
            QueryWrapper<SysUserDept> delQueryWrapper=new QueryWrapper<>();
            delQueryWrapper.lambda().eq(SysUserDept::getDeptId,currentSysDept.getId())
                    .in(SysUserDept::getUserId,deptGroup.keySet())
                    .eq(SysUserDept::getSource,CommonConstants.SOURCE_DING);
            this.sysUserDeptMapper.deletePhysicsById(delQueryWrapper);
        }
    }


    /**
     * 处理历史数据
     * @param dingTalkAsync
     * @param tableName
     */
    private void handleHisData(DingTalkAsync dingTalkAsync,String tableName,boolean isClear){
        //历史表数据
        List<String> hisTableInfo=StringUtils.isNotEmpty(dingTalkAsync.getHisTableInfo())? JSON.parseObject(dingTalkAsync.getHisTableInfo(), List.class):new ArrayList<>();
        String copyTableName=tableName+"_"+ DateUtil.format(new DateTime() , "yyyy_MM_dd_HH_mm_ss");
        try {
            //将最新的表数据复制一份做历史数据
            dingTalkAsyncMapper.copyTable(copyTableName,tableName);
            if(isClear){
                dingTalkAsyncMapper.deleteTableData(tableName);
            }
            //记录下历史表名
            if(hisTableInfo.size()>=3){
                String hisTableName = hisTableInfo.get(0);
                try{
                    //删除掉历史表
                    dingTalkAsyncMapper.dropTable(hisTableName);
                }catch (Exception e){
                    e.printStackTrace();
                }
                hisTableInfo.remove(0);
            }
            hisTableInfo.add(copyTableName);
            dingTalkAsync.setHisTableInfo(JSON.toJSONString(hisTableInfo));
        }catch (Exception e){
            // todo 记录下日志报错信息
            e.printStackTrace();
        }
    }
}
